#include "CMyShortcutWidget.h"
#include "../Common/CCommonFunction.h"
#include "../Common/CMyWindow.h"
#include "../Common/Global/Global.h"
#include "ui_CMyShortcutWidget.h"

#include <QCheckBox>
#include <QDesktopServices>
#include <QDomDocument>
#include <QMenu>
#include <QMessageBox>
#include <QMouseEvent>
#include <QThread>

const QString STR_TITLE = "快捷方式";

const QString FILE_NAME = "Shortcuts.xml";
const QString MODEL_NAME = "MyShortcut";
const QString SHORTCUT_TAG = "Shortcut";
const QString SHORTCUTS_TAG = "Shortcuts";
const QString NAME_TAG = "Name";
const QString PATH_TAG = "Path";
const QString SELECTED_ATTR = "Selected";
const QString VERSION_ATTR = "Version";

QString CMyShortcutWidget::s_strFileName = QString();

CMyShortcutWidget::CMyShortcutWidget(QWidget* parent)
    : CMyWindow(parent),
      ui(new Ui::CMyShortcutWidget)
{
    ui->setupUi(this);

    this->setWindowTitle(STR_TITLE);

    CCommonFunction::GetDataSavePath(s_strFileName);
    s_strFileName += FILE_NAME;

    // 创建菜单组
    initMenubar();

    // 窗口设置
    this->setWindowTitle("快捷方式");

    // 变量初始化
    m_shortcutDialog = new CShortcutDialog(this);

    // 加载文件
    loadFile();

    // 配置listwidget鼠标追踪
    ui->listWidget->setMouseTracking(true);
}

CMyShortcutWidget::~CMyShortcutWidget()
{
    saveFile();

    for (int i = 0; i < m_vShortcuts.size(); i++) {
        if (m_vShortcuts.at(i)) {
            delete m_vShortcuts.at(i);
        }
    }

    m_vShortcuts.clear();

    delete ui;
}

void CMyShortcutWidget::LoadSize(QWidget* parent)
{
    CMyWindow::LoadSizeFromFile(parent, s_strFileName);
}

void CMyShortcutWidget::SaveSize(QWidget* parent)
{
    CMyWindow::SaveSizeToFile(parent, s_strFileName, MODEL_NAME);
}

QMenuBar* CMyShortcutWidget::GetMenuBar()
{
    return m_pMenuBar;
}

int CMyShortcutWidget::GetComponentId()
{
    return 0;
}

void CMyShortcutWidget::addShortcutFromDialog()
{
    // 配置快捷方式对象
    CMyShortcut* shortcut = new CMyShortcut();
    shortcut->setName(m_shortcutDialog->getName());
    shortcut->setPath(m_shortcutDialog->getPath());

    // 存储
    m_vShortcuts.append(shortcut);

    // 添加快捷方式到界面
    addShortcutToWidget(shortcut);
}

void CMyShortcutWidget::fixShortcutFromDialog(int index)
{
    CMyShortcut* shortcut = m_vShortcuts.at(index);

    shortcut->setName(m_shortcutDialog->getName());
    shortcut->setPath(m_shortcutDialog->getPath());
}

void CMyShortcutWidget::addShortcutToWidget(CMyShortcut* shortcut, Qt::CheckState state)
{
    auto pFun = [](void* pData, QString& showText, QString& tipText) {
        CMyShortcut* shortcut = (CMyShortcut*)pData;
        showText = shortcut->getName();
        tipText = shortcut->getPath();
    };

    // 添加到界面
    ui->listWidget->addListWidgetItem(shortcut, pFun, state);
}

bool CMyShortcutWidget::openFile(const QString& path)
{
    QString str = path;
    if (!str.startsWith("file:///")) {
        str = "file:///" + str;
    }

    QUrl url = QUrl(str);
    return QDesktopServices::openUrl(url);
}

void CMyShortcutWidget::saveFile()
{
    QFile file(s_strFileName);

    QDomDocument doc = CCommonFunction::WriteComponentXmlFile(s_strFileName, MODEL_NAME, std::vector<QString>{SHORTCUTS_TAG});

    // xml 根
    QDomElement root = doc.firstChildElement(MODEL_NAME);
    QDomElement shortcutElement = doc.createElement(SHORTCUTS_TAG);
    shortcutElement.setAttribute(VERSION_ATTR, 1);
    root.appendChild(shortcutElement);

    // 开始写入 XML
    int widgetIndex = -1;
    for (int i = 0; i < m_vShortcuts.size(); i++) {
        CMyShortcut* shortcut = m_vShortcuts.at(i);

        // 不为空则可以存储
        if (!shortcut) {
            continue;
        }

        QDomElement elShortcut = doc.createElement(SHORTCUT_TAG);

        // 是否被选中
        QListWidgetItem* item = ui->listWidget->getItem(++widgetIndex);
        if (item) {
            switch (item->checkState()) {
                case Qt::Checked:
                    elShortcut.setAttribute(SELECTED_ATTR, 1);
                    break;

                default:
                    elShortcut.setAttribute(SELECTED_ATTR, 0);
                    break;
            }
        }

        // 快捷方式名
        QDomElement elName = doc.createElement(NAME_TAG);
        QDomText tName = doc.createTextNode(shortcut->getName());
        elName.appendChild(tName);

        // 快捷方式路径
        QDomElement elPath = doc.createElement(PATH_TAG);
        QDomText tPath = doc.createTextNode(shortcut->getPath());
        elPath.appendChild(tPath);

        elShortcut.appendChild(elName);
        elShortcut.appendChild(elPath);

        shortcutElement.appendChild(elShortcut);
    }

    // 打开文件
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        return;
    }
    QTextStream out(&file);
    doc.save(out, 4);

    file.close();
}

void CMyShortcutWidget::loadFile()
{
    QFile file(s_strFileName);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        return;
    }

    QDomDocument doc;
    QString error = "";
    int row = 0, column = 0;

    // 关联 xml 与 文件
    if (!doc.setContent(&file, false, &error, &row, &column)) {
        file.close();
        return;
    }

    file.close();

    QDomElement root = doc.documentElement();
    QDomElement shortcutsElement = root.firstChildElement(SHORTCUTS_TAG);

    if (!shortcutsElement.isNull()) {
        QDomNodeList nodeList = shortcutsElement.childNodes();

        for (int i = 0; i < nodeList.size(); ++i) {
            // 获取 node 节点
            QDomNode node = nodeList.at(i);

            // 配置快捷方式对象
            CMyShortcut* shortcut = new CMyShortcut();
            shortcut->setName(node.firstChildElement(NAME_TAG).text());
            shortcut->setPath(node.firstChildElement(PATH_TAG).text());

            // 保存快捷方式
            m_vShortcuts.append(shortcut);

            // 添加到界面
            Qt::CheckState state = Qt::Unchecked;
            state = node.toElement().attribute(SELECTED_ATTR, "0").toInt() == 1 ? Qt::Checked : Qt::Unchecked;
            addShortcutToWidget(shortcut, state);
        }
    }

    file.close();
}

void CMyShortcutWidget::contextMenuEvent(QContextMenuEvent* event)
{
    QMenu* menu = new QMenu(this);
    menu->addAction(m_pActionAddDirect);
    menu->addAction(m_pActionAddFile);
    menu->addSeparator();
    menu->addAction(m_pActionFix);
    menu->addAction(m_pActionDelete);
    menu->exec(event->globalPos());
    delete menu;
}

void CMyShortcutWidget::initMenubar()
{
    // 创建菜单栏
    m_pMenuBar = new QMenuBar(this);
    m_pMenuBar->hide();

    // 文件菜单
    m_pMenuFile = m_pMenuBar->addMenu("文件");
    m_pActionAddDirect = m_pMenuFile->addAction("添加文件夹...");
    m_pActionAddFile = m_pMenuFile->addAction("添加文件...");
    m_pMenuBar->addSeparator();
    m_pActionFix = m_pMenuFile->addAction("修改...");
    m_pActionDelete = m_pMenuFile->addAction("删除");
    m_pMenuBar->addSeparator();
    m_pActionExit = m_pMenuFile->addAction("退出");

    connect(m_pActionAddDirect, SIGNAL(triggered()), this, SLOT(slotActionAddDirect()));
    connect(m_pActionAddFile, SIGNAL(triggered()), this, SLOT(slotActionAddFile()));
    connect(m_pActionFix, SIGNAL(triggered()), this, SLOT(slotActionFix()));
    connect(m_pActionDelete, SIGNAL(triggered()), this, SLOT(slotActionDelete()));
    connect(m_pActionExit, &QAction::triggered, [this]() {
        emit this->signalClose();
    });
}

void CMyShortcutWidget::setMainWindowStatusText(const QString& text)
{
    QFontMetrics metrics(g_fontStatusBar);
    QString str = text;
    int width = this->size().width() - 30;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    if (metrics.width(text) > width) {
        str = metrics.elidedText(str, Qt::ElideLeft, width);
    }
#else
    QRect rect = metrics.boundingRect(text);
    if (rect.width() > width) {
        str = metrics.elidedText(str, Qt::ElideLeft, width);
    }
#endif

    emit signalSetStatusText(str);
}

void CMyShortcutWidget::on_btnOpen_clicked()
{
    int count = 0;
    // 打开所有被选中的快捷方式
    QVector<void*> vData = ui->listWidget->getCheckedItemData();
    for (int i = 0; i < vData.size(); i++) {
        CMyShortcut* shortcut = (CMyShortcut*)(vData.at(i));

        // 打开文件并记录失败个数
        if (!openFile(shortcut->getPath())) {
            ++count;
        }
        else {
            QThread::msleep(200);
        }
    }

    if (count > 0) {
        QMessageBox::warning(this, "警告", QString("有 %1 个文件打开失败").arg(count));
    }
}

void CMyShortcutWidget::on_listWidget_itemEntered(QListWidgetItem* item)
{
    // 将当前路径显示到状态栏
    CMyListWidgetItem* listItem = dynamic_cast<CMyListWidgetItem*>(item);
    if (listItem) {
        CMyShortcut* shortcut = (CMyShortcut*)listItem->getItemData();
        setMainWindowStatusText(shortcut->getPath());
    }
}

void CMyShortcutWidget::on_listWidget_itemClicked(QListWidgetItem* item)
{
    // 将当前路径显示到状态栏
    CMyListWidgetItem* listItem = dynamic_cast<CMyListWidgetItem*>(item);
    if (listItem) {
        CMyShortcut* shortcut = (CMyShortcut*)listItem->getItemData();
        setMainWindowStatusText(shortcut->getPath());
    }
}

void CMyShortcutWidget::on_listWidget_doubleClicked(const QModelIndex& index)
{
    CMyShortcut* shortcut = (CMyShortcut*)ui->listWidget->getItemData(index.row());

    // 处理中文路径会出错
    if (shortcut && !openFile(shortcut->getPath())) {
        QMessageBox::critical(this, "错误", "文件或文件夹打开失败！");
    }
}

void CMyShortcutWidget::slotActionAddFile()
{
    if (m_shortcutDialog->execMyDialog() == QDialog::Accepted) {
        addShortcutFromDialog();
    }
}

void CMyShortcutWidget::slotActionAddDirect()
{
    if (m_shortcutDialog->execMyDialog(false) == QDialog::Accepted) {
        addShortcutFromDialog();
    }
}

void CMyShortcutWidget::slotActionFix()
{
    int index = ui->listWidget->currentIndex().row();
    if (index != -1) {
        CMyShortcut* shortcut = (CMyShortcut*)ui->listWidget->getItemData(index);
        if (m_shortcutDialog->execMyDialog(shortcut, QFileInfo(shortcut->getPath()).isFile()) == QDialog::Accepted) {
            fixShortcutFromDialog(ui->listWidget->getItemId(index));

            ui->listWidget->updateShowText(index);
        }
    }
}

void CMyShortcutWidget::slotActionDelete()
{
    int row = ui->listWidget->currentIndex().row();
    if (row >= 0) {
        int nId = ui->listWidget->removeItem(row);

        // 释放容器中的对象
        delete m_vShortcuts[nId];
        m_vShortcuts[nId] = nullptr;
    }
    else {
        QMessageBox::critical(this, "错误", "当前没有选中项");
    }
}
